package com.vc.demo.crypto;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.vc.demo.model.OpenResult;
import com.vc.demo.model.Payload;
import com.vc.demo.utils.TimeUtils;


import java.security.*;
import java.util.*;

public class SecurityUtil {

    private static final String PUB3 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApIv4bgz4SZ60XwUBJueFiyUNcK7D9I0e QauI1yR8XJOuUEI9jgq7WkdJCzldWzrCQT9twgON+HCnDN+6QhIUnMVBe6ozW0Yc0+BbtrUIO+5o 9aiqKtqk13isgC0kDl24sLHUhCUyF/phmKNEk8g862RElRF9yq82b/a04Lpom1TXupNJCIbAjb6e sg1Cw3QAWErtD91mFAwyiEWM1UovlXjor3PUmtTeqbyFoVSzHS02yVG8Ge+JIDCWrZGCh9ShTzgR YKYqdNiFjG45W84V732YatobDIF/RUWg5dXWZPLCqxzXBDcrdnrwF7vRHyHrKjuKHr69vB6/b509 /easYwIDAQAB";
    /**
     * 密钥对1
     */
    private static String PUB2 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg5rzaDl7pGDjc0Ho2Oh/jD7sKR1p5ELS Xu+k7BLm0rToHoQc6Z2n6+RhCREAxAPFNRqJEb3jbmViyyASS3eJk63X+LB7c0UT/rVbHBiLywym ef3zShMr44HoXnWpCvnU+g67ZmW+xHobnHrWo4wMNaAUHuVmE/HotcPzHRWjhj49SfWNpfERKgdx P7wlKt4bq2EiUxquPIXGjQ6xudmYOG7nvWWlp6BpKJVpLfCEzjP924LBBRNaDMo+LL3RjYA5jqFM gs0LlOhIFl2JkJyQYjBf+qbQGFyyHG9RXpQz1ijH0tFhrLWrf+HzVT3RdlVMbd7BKdRALJKAiCog W01XJQIDAQAB";
    private static String PRI2 = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCDmvNoOXukYONzQejY6H+MPuwp HWnkQtJe76TsEubStOgehBzpnafr5GEJEQDEA8U1GokRveNuZWLLIBJLd4mTrdf4sHtzRRP+tVsc GIvLDKZ5/fNKEyvjgehedakK+dT6DrtmZb7EehucetajjAw1oBQe5WYT8ei1w/MdFaOGPj1J9Y2l 8REqB3E/vCUq3hurYSJTGq48hcaNDrG52Zg4bue9ZaWnoGkolWkt8ITOM/3bgsEFE1oMyj4svdGN gDmOoUyCzQuU6EgWXYmQnJBiMF/6ptAYXLIcb1FelDPWKMfS0WGstat/4fNVPdF2VUxt3sEp1EAs koCIKiBbTVclAgMBAAECggEAT/83aCpQ8wmGGMB+pqMlLP3ulctwW7UWpWisamfO8VPQKQSLgqI3 uZc4OMeiHIRiMrZvjV5MygVM+UYEeOUvtpocxumYEOhzkAdzW2+8Qe/tngf1BBkFO6Tyt8Bzwd09 Tcb4uPSt8kZ7VDIDGKT/ovUsZd9xnjwVBbAXrp1Bqk52+ND0rsQvAPVdS3IFwRo23mqZn19RGBRJ w4eX5xePgVRX5AwSjmTr7g4hom8lIcsHW5SFUf4j+8KAy/ssLkg9jXD8hG4sipKaNnhS9qWicsgS BCP3Gu6ERADfV+aW37yL8HJd/KxFYBYgVynr6b6l9Te+Dcbkl8K1g01DV2rPHQKBgQDXVmpqZ+WN 18sNjil2yUDgHCK4P0GxVm4cc+2C6UudlRvydUYygVQrQ5bYndfnN+tWwfKGqdYmntbde3dIcD6Y PRW8s4BqCM8o6IG3zApPjnrzrHjGzOqf22xz/0zReEroW53t6gSFF5lHuHyxAHqiQNOxfTce/xO4 ptsAW5wAHwKBgQCcdNoJAYsUp6twUN6jLf4qWkNoQlQfnEqp5m5fFxeFdQmGUXki3uS1GBAaj8UT 841swKoP1mM2QfXXfyhr5DikFxu/Elom5GsxJxhJe0Hs32NeTsv/L93oaoenOgHklbbHMAJ9AEkL pXvQSoeXuD1PAi0RHehlq5TdpuclKTywOwKBgBQlFnF75MK/RFSxTvm43CPbHfhkmo2viz+ILNkJ YDSOxX2KMRX6eVhOy2baZV9RIOgN3tVwQAN+6pTvvvn83i450LXFiSbiShcGoVQDd5d3udLf+LCI bQ6lZWD4qkQSX9ea8oxWTzPwQDuwa6HXbKGPNP6uuyBgNoUYvvYqm857AoGBAIV5UsE4JdTbLfDF rQn9JMYw9yys2WOWTEQhp6tL4e8i55tFSlirWuX7v1FJsdHRh6dtvieAuGcDYp4ThwJ0UrX6WNtq 5qojWCc4uQmHM7jG4tkD1BjCV0f+CfhqDk9aQfIwTQ8i/S4IYVZTHtYagYMz0gq2PxrthDSMPMmB IpsdAoGBAMrbO7frLo4DBeU1LUdO9rUt2lgJEWzk2P4wdz6aXjb7GD4h+DWoF/MDY9yKyp/Ln+uZ j2mX6kv4m2AiZBrV4UvwqZUmRpO69wjQe0eWtQXKgCnCL6lPXyBSDaCreAtyVbcTNXLOAlG+NQCU fi9eY4gRYlIZuI2KlDpZQ9jNQtR3";
    /**
     * 密钥对2
     */
    private static String PUB1 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg5rzaDl7pGDjc0Ho2Oh/jD7sKR1p5ELS Xu+k7BLm0rToHoQc6Z2n6+RhCREAxAPFNRqJEb3jbmViyyASS3eJk63X+LB7c0UT/rVbHBiLywym ef3zShMr44HoXnWpCvnU+g67ZmW+xHobnHrWo4wMNaAUHuVmE/HotcPzHRWjhj49SfWNpfERKgdx P7wlKt4bq2EiUxquPIXGjQ6xudmYOG7nvWWlp6BpKJVpLfCEzjP924LBBRNaDMo+LL3RjYA5jqFM gs0LlOhIFl2JkJyQYjBf+qbQGFyyHG9RXpQz1ijH0tFhrLWrf+HzVT3RdlVMbd7BKdRALJKAiCog W01XJQIDAQAB";
    private static String PRI1 = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCDmvNoOXukYONzQejY6H+MPuwp HWnkQtJe76TsEubStOgehBzpnafr5GEJEQDEA8U1GokRveNuZWLLIBJLd4mTrdf4sHtzRRP+tVsc GIvLDKZ5/fNKEyvjgehedakK+dT6DrtmZb7EehucetajjAw1oBQe5WYT8ei1w/MdFaOGPj1J9Y2l 8REqB3E/vCUq3hurYSJTGq48hcaNDrG52Zg4bue9ZaWnoGkolWkt8ITOM/3bgsEFE1oMyj4svdGN gDmOoUyCzQuU6EgWXYmQnJBiMF/6ptAYXLIcb1FelDPWKMfS0WGstat/4fNVPdF2VUxt3sEp1EAs koCIKiBbTVclAgMBAAECggEAT/83aCpQ8wmGGMB+pqMlLP3ulctwW7UWpWisamfO8VPQKQSLgqI3 uZc4OMeiHIRiMrZvjV5MygVM+UYEeOUvtpocxumYEOhzkAdzW2+8Qe/tngf1BBkFO6Tyt8Bzwd09 Tcb4uPSt8kZ7VDIDGKT/ovUsZd9xnjwVBbAXrp1Bqk52+ND0rsQvAPVdS3IFwRo23mqZn19RGBRJ w4eX5xePgVRX5AwSjmTr7g4hom8lIcsHW5SFUf4j+8KAy/ssLkg9jXD8hG4sipKaNnhS9qWicsgS BCP3Gu6ERADfV+aW37yL8HJd/KxFYBYgVynr6b6l9Te+Dcbkl8K1g01DV2rPHQKBgQDXVmpqZ+WN 18sNjil2yUDgHCK4P0GxVm4cc+2C6UudlRvydUYygVQrQ5bYndfnN+tWwfKGqdYmntbde3dIcD6Y PRW8s4BqCM8o6IG3zApPjnrzrHjGzOqf22xz/0zReEroW53t6gSFF5lHuHyxAHqiQNOxfTce/xO4 ptsAW5wAHwKBgQCcdNoJAYsUp6twUN6jLf4qWkNoQlQfnEqp5m5fFxeFdQmGUXki3uS1GBAaj8UT 841swKoP1mM2QfXXfyhr5DikFxu/Elom5GsxJxhJe0Hs32NeTsv/L93oaoenOgHklbbHMAJ9AEkL pXvQSoeXuD1PAi0RHehlq5TdpuclKTywOwKBgBQlFnF75MK/RFSxTvm43CPbHfhkmo2viz+ILNkJ YDSOxX2KMRX6eVhOy2baZV9RIOgN3tVwQAN+6pTvvvn83i450LXFiSbiShcGoVQDd5d3udLf+LCI bQ6lZWD4qkQSX9ea8oxWTzPwQDuwa6HXbKGPNP6uuyBgNoUYvvYqm857AoGBAIV5UsE4JdTbLfDF rQn9JMYw9yys2WOWTEQhp6tL4e8i55tFSlirWuX7v1FJsdHRh6dtvieAuGcDYp4ThwJ0UrX6WNtq 5qojWCc4uQmHM7jG4tkD1BjCV0f+CfhqDk9aQfIwTQ8i/S4IYVZTHtYagYMz0gq2PxrthDSMPMmB IpsdAoGBAMrbO7frLo4DBeU1LUdO9rUt2lgJEWzk2P4wdz6aXjb7GD4h+DWoF/MDY9yKyp/Ln+uZ j2mX6kv4m2AiZBrV4UvwqZUmRpO69wjQe0eWtQXKgCnCL6lPXyBSDaCreAtyVbcTNXLOAlG+NQCU fi9eY4gRYlIZuI2KlDpZQ9jNQtR3";

    /**
     * 签名字段
     */
    private static final String SIGNATURE_FIELD = "signature";
    /**
     * 加密字段
     */
    private static final String ENCRYPT_FIELD = "bizData";

    private static final String ENCRYPT_FIELD_DATA = "data";

    /**
     * 随机加密因子字段
     */
    private static final String ENCRYPT_RANDOMKEY_FIELD = "encryptedRandomKey";

    public static void main(String[] args) throws Exception {
//        Payload payload = new Payload();
//
//        payload.setRequestId(1234l+"");
//        payload.setTimestamp(TimeUtils.format_yyyyMMddHHmmss(new Date()));
//        payload.setApiKey("CD8D9B55376B5612B23AC282FF3EE6BC");
//
//        payload.setEncryptedRandomKey(null);
//        payload.setSignature(null);
//        Map<String, String> bizData = new HashMap<>();
//        bizData.put("type", "1");
//        bizData.put("validSeconds", "100");
//        bizData.put("extId", "100");
//        bizData.put("bgImgBase64", "");
//        payload.setBizData(bizData);
//        System.out.println("原始数据=>" + JSON.toJSONString(payload));
//        String text = encrypt(JSON.toJSONString(payload), PUB2);
//        System.out.println("加密后=>" + text + "\n");
//        // 签名
//        String text1 = sign(text, PRI1);
//        System.out.println("签名后=>" + text1);
//        // text1 发送给对方，对方 先验证签名-PUB1, 然后解密-PRI2
//        boolean ok = verify(text1, PUB1);
//        System.out.println("签名验证=>" + ok);
//        // 解密 - PRI1
////        String text2 = decrypt2(text1, PRI2);
//        decrypt(text1,PRI1);

//        String[] array =  genKeyPairs();
//        for (String item: array){
//            System.out.println(item);
//        }

    }

    /**
     * 兑换
     * @throws Exception
     */

    private static String[] genKeyPairs() throws Exception {

        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom secureRandom = new SecureRandom();

        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        keyPairGenerator.initialize(2048, secureRandom);
        //keyPairGenerator.initialize(KEYSIZE);
        /** 生成密匙对 */
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        /** 得到公钥 */
        Key publicKey = keyPair.getPublic();
        /** 得到私钥 */
        Key privateKey = keyPair.getPrivate();
        byte[] publicKeyBytes = publicKey.getEncoded();
        byte[] privateKeyBytes = privateKey.getEncoded();
        String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKeyBytes);
        String privateKeyBase64 =  Base64.getEncoder().encodeToString(privateKeyBytes);

        return new String[]{privateKeyBase64, publicKeyBase64};
    }
    public static String severEncryptAndSign(OpenResult result, String tenantPublicKey, String severPrivateKey) throws Exception {

        String aesRandomKey = AlgorithmUtil.getAESRandomKey();
        String randomKeyEncrypted = AlgorithmUtil.encryptWithRSA(aesRandomKey, tenantPublicKey);

        // 加密
        String parameterJsonEncrypted = AlgorithmUtil.encryptWithAES(JSON.toJSONString(result.getData()), aesRandomKey);
        result.setData(parameterJsonEncrypted);
        result.setEncryptedRandomKey(randomKeyEncrypted);

        // 签名
        JSONObject origData = JSONObject.parseObject(JSON.toJSONString(result));
        origData = origData.fluentRemove(SIGNATURE_FIELD);
        String signtext = AlgorithmUtil.sign(getNatureSortedJSONObject(origData), severPrivateKey);

        result.setSignature(signtext);
        return JSONObject.toJSONString(result);
    }
    /**
     * 加密(带随机值)
     *
     * @return
     * @throws Exception
     */
    public static String encrypt(String data, String key) throws Exception {
        try {
            JSONObject origData = JSONObject.parseObject(data);
            String aesRandomKey = AlgorithmUtil.getAESRandomKey();
            System.out.println("aesRandomKey=>" + aesRandomKey);
            String randomKeyEncrypted = AlgorithmUtil.encryptWithRSA(aesRandomKey, key);
            String parameterJsonEncrypted = AlgorithmUtil.encryptWithAES(origData.getJSONObject(ENCRYPT_FIELD).toJSONString(), aesRandomKey);
            origData.put(ENCRYPT_RANDOMKEY_FIELD, randomKeyEncrypted);
            origData.put(ENCRYPT_FIELD, parameterJsonEncrypted);
            return origData.toJSONString();
        } catch (Exception e) {
            System.out.println("业务加密失败，原因=>" + e.getMessage());
            throw new Exception("业务加密失败");
        }
    }

    /**
     * 解密
     * @param data
     * @return
     * @throws Exception
     */
    public static String decrypt(String data, String key) throws Exception {
        try {
            JSONObject origData = JSONObject.parseObject(data);

            String randomKeyEncrypted = origData.getString(ENCRYPT_RANDOMKEY_FIELD);
            System.out.println("随机数密文：" + randomKeyEncrypted);
            String randomKey = AlgorithmUtil.decryptWithRSA(randomKeyEncrypted, key);
            System.out.println("随机数原文：" + randomKey);
            System.out.println("业务数据密文：" + origData.getString(ENCRYPT_FIELD));
            String bizData = AlgorithmUtil.decryptWithAES(origData.getString(ENCRYPT_FIELD), randomKey);

            System.out.println("业务数据原文：" + bizData);
            origData.put(ENCRYPT_FIELD, bizData);
            origData = origData.fluentRemove(ENCRYPT_RANDOMKEY_FIELD);
            return origData.toJSONString();
        } catch (Exception e) {
            System.out.println("业务数据解密失败，原因=>" + e.getMessage());
            throw new Exception("业务数据解密失败");
        }
    }


    /**
     * 签名
     *
     * @return
     * @throws Exception
     */
    public static String sign(String data, String key) throws Exception {
        try {
            JSONObject origData = JSONObject.parseObject(data);
            origData = origData.fluentRemove(SIGNATURE_FIELD);
            String signData = AlgorithmUtil.sign(getNatureSortedJSONObject(origData), key);
            origData.put(SIGNATURE_FIELD, signData);
            return origData.toJSONString();
        } catch (GeneralSecurityException e) {
            System.out.println("签名失败，原因=>" + e.getMessage());
            throw new Exception("签名失败");
        }
    }

    /**
     * 验证签名
     * @param data
     * @return
     */
    public static boolean verify(String data, String key){
        try {
            JSONObject request = JSONObject.parseObject(data);

            //验证签名
            String signData = request.getString(SIGNATURE_FIELD);
            request = request.fluentRemove(SIGNATURE_FIELD);
            return AlgorithmUtil.verify(getNatureSortedJSONObject(request), key, signData);
        } catch (Exception e) {
            System.out.println("验证签名失败，原因=>" + e.getMessage());
        }
        return false;
    }

    /**w!
     *
     * 字典排序
     *
     * @param origJSONObject
     * @return
     */
    private static String getNatureSortedJSONObject(JSONObject origJSONObject) {
        System.out.println("=======================================");
        System.out.println(origJSONObject.toJSONString());
        Map<String, Object> treeMap = new TreeMap<String, Object>();
        Set<String> sendJOKeySet = origJSONObject.keySet();
        for (Iterator<String> iterator = sendJOKeySet.iterator(); iterator.hasNext(); ) {
            String sendJOKey = iterator.next();
            treeMap.put(sendJOKey, origJSONObject.get(sendJOKey));
        }
        String sortedJSON = new JSONObject(treeMap).toJSONString();
        System.out.println(sortedJSON);
        return sortedJSON;
    }
}
